<!DOCTYPE HTML>
<html>
<!--
Tests for Mixed Content Blocker
https://bugzilla.mozilla.org/show_bug.cgi?id=62178
-->
<head>
  <meta charset="utf-8">
  <title>Tests for Bug 62178</title>
  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
</head>
<body>
<div id="testContent"></div>

<!-- types the Mixed Content Blocker can block
     /*
  switch (aContentType) {
  case nsIContentPolicy::TYPE_OBJECT:
  case nsIContentPolicy::TYPE_SCRIPT:
  case nsIContentPolicy::TYPE_STYLESHEET:
  case nsIContentPolicy::TYPE_SUBDOCUMENT:
  case nsIContentPolicy::TYPE_XMLHTTPREQUEST:

  case nsIContentPolicy::TYPE_FONT: - NO TEST:
    Load events for external fonts are not detectable by javascript.
  case nsIContentPolicy::TYPE_WEBSOCKET: - NO TEST:
    websocket connections over https require an encrypted websocket protocol (wss:)

  case nsIContentPolicy::TYPE_IMAGE:
  case nsIContentPolicy::TYPE_IMAGESET:
  case nsIContentPolicy::TYPE_MEDIA:
  case nsIContentPolicy::TYPE_PING:
    our ping implementation is off by default and does not comply with the current spec (bug 786347)
  case nsIContentPolicy::TYPE_BEACON:

  }
     */
-->

<script>
  var baseUrl = "http://example.com/tests/dom/security/test/mixedcontentblocker/file_server.sjs";

  //For tests that require setTimeout, set the maximum polling time to 100 x 100ms = 10 seconds.
  var MAX_COUNT = 100;
  var TIMEOUT_INTERVAL = 100;

  var testContent = document.getElementById("testContent");

  /* Part 1: Mixed Script tests */

  // Test 1a: insecure object
  var object = document.createElement("object");
  object.data = baseUrl + "?type=object";
  object.type = "application/x-test";
  object.width = "200";
  object.height = "200";

  testContent.appendChild(object);

  var objectCount = 0;

  function objectStatus(object) {
    // Expose our privileged bits on the object
    object = SpecialPowers.wrap(object);

    if (object.displayedType != SpecialPowers.Ci.nsIObjectLoadingContent.TYPE_NULL) {
      //object loaded
      parent.postMessage({"test": "object", "msg": "insecure object loaded"}, "http://mochi.test:8888");
    }
    else {
      if(objectCount < MAX_COUNT) {
        objectCount++;
        setTimeout(objectStatus, TIMEOUT_INTERVAL, object);
      }
      else {
        //After we have called setTimeout the maximum number of times, assume object is blocked
        parent.postMessage({"test": "object", "msg": "insecure object blocked"}, "http://mochi.test:8888");
      }
    }
  }

  // object does not have onload and onerror events. Hence we need a setTimeout to check the object's status
  setTimeout(objectStatus, TIMEOUT_INTERVAL, object);

  // Test 1b: insecure script
  var script = document.createElement("script");
  var scriptLoad = false;
  var scriptCount = 0;
  script.src = baseUrl + "?type=script";
  script.onload = function() {
    parent.postMessage({"test": "script", "msg": "insecure script loaded"}, "http://mochi.test:8888");
    scriptLoad = true;
  }
  testContent.appendChild(script);

  function scriptStatus(script)
  {
    if(scriptLoad) {
      return;
    }
    else {
      if(scriptCount < MAX_COUNT) {
        scriptCount++;
        setTimeout(scriptStatus, TIMEOUT_INTERVAL, script);
      }
      else {
        //After we have called setTimeout the maximum number of times, assume script is blocked
        parent.postMessage({"test": "script", "msg": "insecure script blocked"}, "http://mochi.test:8888");
      }
    }
  }

  // scripts blocked by Content Policy's do not have onerror events (see bug 789856).  Hence we need a setTimeout to check the script's status
  setTimeout(scriptStatus, TIMEOUT_INTERVAL, script);


  // Test 1c: insecure stylesheet
  var cssStyleSheet = document.createElement("link");
  cssStyleSheet.rel = "stylesheet";
  cssStyleSheet.href = baseUrl + "?type=stylesheet";
  cssStyleSheet.type = "text/css";
  testContent.appendChild(cssStyleSheet);

  var styleCount = 0;

  function styleStatus(cssStyleSheet) {
    if( cssStyleSheet.sheet || cssStyleSheet.styleSheet || cssStyleSheet.innerHTML ) {
      parent.postMessage({"test": "stylesheet", "msg": "insecure stylesheet loaded"}, "http://mochi.test:8888");
    } 
    else {
      if(styleCount < MAX_COUNT) {
        styleCount++;
        setTimeout(styleStatus, TIMEOUT_INTERVAL, cssStyleSheet);
      }
      else {
        //After we have called setTimeout the maximum number of times, assume stylesheet is blocked
        parent.postMessage({"test": "stylesheet", "msg": "insecure stylesheet blocked"}, "http://mochi.test:8888");
      }
    }
  }

  // link does not have onload and onerror events. Hence we need a setTimeout to check the link's status
  window.setTimeout(styleStatus, TIMEOUT_INTERVAL, cssStyleSheet);

  // Test 1d: insecure iframe
  var iframe = document.createElement("iframe");
  iframe.src = baseUrl + "?type=iframe";
  iframe.onload = function() {
    parent.postMessage({"test": "iframe", "msg": "insecure iframe loaded"}, "http://mochi.test:8888");
  }
  iframe.onerror = function() {
    parent.postMessage({"test": "iframe", "msg": "insecure iframe blocked"}, "http://mochi.test:8888");
  };
  testContent.appendChild(iframe);


  // Test 1e: insecure xhr
  var xhr = new XMLHttpRequest;
  try {
    xhr.open("GET", baseUrl + "?type=xhr", true);
    xhr.send();
    xhr.onloadend = function (oEvent) {
      if (xhr.status == 200) {
        parent.postMessage({"test": "xhr", "msg": "insecure xhr loaded"}, "http://mochi.test:8888");
      }
      else {
        parent.postMessage({"test": "xhr", "msg": "insecure xhr blocked"}, "http://mochi.test:8888");
      }
    }
  } catch(ex) {
     parent.postMessage({"test": "xhr", "msg": "insecure xhr blocked"}, "http://mochi.test:8888");
  }

  /* Part 2: Mixed Display tests */

  // Shorthand for all image test variants
  function imgHandlers(img, test) {
    img.onload = function () {
      parent.postMessage({"test": test, "msg": "insecure image loaded"}, "http://mochi.test:8888");
    }
    img.onerror = function() {
      parent.postMessage({"test": test, "msg": "insecure image blocked"}, "http://mochi.test:8888");
    }
  }

  // Test 2a: insecure image
  var img = document.createElement("img");
  img.src = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
  imgHandlers(img, "image");
  // We don't need to append the image to the document. Doing so causes the image test to run twice.

  // Test 2b: insecure media
  var media = document.createElement("video");
  media.src = "http://mochi.test:8888/tests/dom/media/test/320x240.ogv?" + Math.floor((Math.random()*1000)+1);
  media.width = "320";
  media.height = "200";
  media.type = "video/ogg";
  media.onloadeddata = function() {
    parent.postMessage({"test": "media", "msg": "insecure media loaded"}, "http://mochi.test:8888");
  }
  media.onerror = function() {
    parent.postMessage({"test": "media", "msg": "insecure media blocked"}, "http://mochi.test:8888");
  }
  // We don't need to append the video to the document. Doing so causes the image test to run twice.

  /* Part 3: Mixed Active Tests for Image srcset */

  // Test 3a: image with srcset
  var imgA = document.createElement("img");
  imgA.srcset = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
  imgHandlers(imgA, "imageSrcset");

  // Test 3b: image with srcset, using fallback from src, should still use imageset policy
  var imgB = document.createElement("img");
  imgB.srcset = " ";
  imgB.src = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
  imgHandlers(imgB, "imageSrcsetFallback");

  // Test 3c: image in <picture>
  var imgC = document.createElement("img");
  var pictureC = document.createElement("picture");
  var sourceC = document.createElement("source");
  sourceC.srcset = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
  pictureC.appendChild(sourceC);
  pictureC.appendChild(imgC);
  imgHandlers(imgC, "imagePicture");

  // Test 3d: Loaded basic image switching to a <picture>, loading
  //          same source, should still redo the request with new
  //          policy.
  var imgD = document.createElement("img");
  imgD.src = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
  imgD.onload = imgD.onerror = function() {
    // Whether or not it loads, we want to now append it to a picture and observe
    var pictureD = document.createElement("picture");
    var sourceD = document.createElement("source");
    sourceD.srcset = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
    pictureD.appendChild(sourceD);
    pictureD.appendChild(imgD);
    imgHandlers(imgD, "imageJoinPicture");
  }

  // Test 3e: img load from <picture> source reverts to img.src as it
  //          is removed -- the new request should revert to mixed
  //          display policy
  var imgE = document.createElement("img");
  var pictureE = document.createElement("picture");
  var sourceE = document.createElement("source");
  sourceE.srcset = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
  pictureE.appendChild(sourceE);
  pictureE.appendChild(imgE);
  imgE.src = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
  imgE.onload = imgE.onerror = function() {
    // Whether or not it loads, remove it from the picture and observe
    pictureE.removeChild(imgE)
    imgHandlers(imgE, "imageLeavePicture");
  }

</script>
</body>
</html>
